home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Communication / Weather / Source / state.c < prev    next >
C/C++ Source or Header  |  1993-11-14  |  8KB  |  347 lines

  1. /*
  2.  * State machine and menu abstraction.
  3.  * The idea is to keep as much of the hookup dialog
  4.  * as possible in a text file, so that menus and hookup protocols
  5.  * are easy to change here or in other apps.
  6.  * It has grown a few warts.
  7.  *
  8.  * M. J. Hawley
  9.  * mike@media-lab.mit.edu
  10.  * Copyright (c) November 1991, MIT Media Laboratory.
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <libc.h>
  17. #include "util.h"
  18. #include "state.h"
  19. #include "StormFunc.h"
  20.  
  21. #define MENU 1
  22.  
  23. SType lastType = Plain;
  24.  
  25.  
  26. static char *getStr(char *s, char *t) {
  27.     char end = ' ';
  28.  
  29.     *t = '\0';
  30.     s = skipsp(s);
  31.     lastType = Plain;
  32.     switch (*s){
  33.     case '/': lastType = Pattern;
  34.     Case '+': lastType = Status; s++;
  35.     Case '!': lastType = CmdS; s++;
  36.     Case ',': lastType = FlushS; s++;
  37.     Case '=': lastType = Goto; s = skipsp(s+2);
  38.     }
  39.  
  40.     if (*s=='/' || *s == '"') end = *s++;
  41.     while (*s && !(*s == end || (end==' ' && *s == '\t'))){
  42.         *t = *s++;
  43.         if (*t == '\\') switch (*s){
  44.             case 'n': *t = '\n'; s++;
  45.             Case 't': *t = '\t'; s++;
  46.             Case 'b': *t = '\b'; s++;
  47.             Default : *t = *s; s++;
  48.         }
  49.         t++;
  50.     }
  51.     *t = '\0';
  52.     if (*s && *s != ' ' && *s != '\t') ++s;
  53.     if (*s) s = skipsp(s);
  54.     return s;
  55. }
  56.  
  57. static State *
  58. newMenu(char *s) {
  59.     State *S = Alloc(State);
  60.     char n[1024], first[1024], last[1024], label[1024];
  61.     s = skipsp(skipsp(s)+4);
  62.     sscanf(s,"%[^:]",n);
  63.     s = skipsp(index(s,':')+1);
  64.     s = getStr(s,first);
  65.     s = getStr(s,last);
  66.     s = getStr(s,label); 
  67.     S->name = save(n);
  68.     S->label = save(label);
  69.     S->first = save(first);
  70.     S->last = save(last);
  71.     S->type = MENU;
  72.     return S;
  73. }
  74.  
  75. static State *
  76. newState(char *s) {
  77.     State *S = Alloc(State);
  78.     S->name = save(s);
  79.     return S;
  80. }
  81.  
  82. static String *
  83. addStr(String *s, char *t) {
  84.     String *start = s, *n = Alloc(String);
  85.     char *p;
  86.     
  87.     p = n->s = save(t);
  88.     if (*p=='/' && (p = index(p+1,'/'))){
  89.         while (p[-1]=='\\') p = index(p+1,'/');
  90.         if (p) *p = '\0';
  91.     }
  92.     
  93.     if (!s) return n;
  94.     while (s->next) s = s->next;
  95.     s->next = n;
  96.     return start;
  97. }
  98.  
  99. static void stripq(char *s) {
  100.     if (*s == '\"'){
  101.         strcpy(s,s+1);
  102.         if (s = rindex(s,'\"')) *s = '\0';
  103.     }
  104. }
  105.  
  106. static void
  107. addMenu(State *S, char *s) {
  108.     char send[1024], get[1024], label[1024];
  109.     MenuItem *m = Alloc(MenuItem), *t;
  110.     s = getStr(s,send); m->send = save(send);
  111.     s = getStr(s,get); m->get = save(get);
  112.     skipsp(s); strcpy(label,s); stripnl(label); stripq(label); m->label = save(label);
  113.     for (t=S->m; t && t->next; t = t->next) ;
  114.     if (t) t->next = m; else S->m = m;
  115. }
  116.  
  117. static void
  118. addString(State *S, char *s) {
  119.     stripnl(s=skipsp(s));
  120.     S->l = addStr(S->l,s);
  121. }
  122.  
  123. #define MaxS 256
  124. static State *ST[MaxS];
  125. static int NS = 0;
  126.  
  127. static void
  128. readState(FILE *f) {
  129.     char s[1024], n[1024];
  130.     State *S = (State *)0;
  131.     while (fgets(s,sizeof s,f)){
  132.         stripcomment(s);
  133.         if (blank(s)) continue;
  134.         if (strncmp(s,"Menu",4)==0){
  135.             S = newMenu(s);
  136.             ST[NS++] = S;
  137.         } else
  138.         if (match(s,"[a-zA-Z]*:")){
  139.             sscanf(s,"%[^:]",n);
  140.             S = newState(n);
  141.             ST[NS++] = S;
  142.         } else
  143.         if (S){
  144.             if (S->type == MENU) addMenu(S,s); else
  145.                                  addString(S,s);
  146.         }
  147.     }
  148. }
  149.  
  150. State*
  151. state(char *s) {
  152.     int i;
  153.     s = skipsp(s);
  154.     for (i=0;i<NS;i++)
  155.         if (strcmp(s,ST[i]->name)==0) return ST[i];
  156.     return (State *)0;
  157. }
  158.  
  159.  
  160. /*
  161. static char *str(char *s) { return s? s : ""; }
  162.  
  163. static void
  164. printState(State *s) {
  165.     if (!s) {
  166.         printf("huh?\n");
  167.     return;
  168.     }
  169.     printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label));
  170. }
  171. */
  172.  
  173. void
  174. ReadState(char *s) {
  175.     FILE *f;
  176.     if (!NS){
  177.         f = fopen(s,"r");
  178.         if (f) readState(f), fclose(f);
  179.     }
  180.     setState("Attach");
  181.     setMenu("Main");
  182. }
  183.  
  184. State *curState = (State *)0;
  185.  
  186. void
  187. setState(char *s) {
  188.     curState = state(s);
  189.     if (strcmp(s,"Detach")==0) logout();
  190.     if (strcmp(s,"Ready")==0) fetchReports();
  191. }
  192.  
  193. static void
  194. execute(char *s) {
  195.     char t[1024];
  196.  
  197.     if (s[0]=='/') s += strlen(s)+1;
  198.     while ((s=getStr(s,t)) && *t) switch (lastType){
  199.         case CmdS:    Command(t);
  200.         Case Status : message(t);
  201.         Case Plain  : if (!state(t)) Put("%s",t);
  202.         Case FlushS : Flush(t);
  203.         Case Goto   : setState(t);
  204.     Case Pattern: break;
  205.     Case Pause  : break;
  206.     }
  207. }
  208.  
  209. void
  210. execState(State *s, char *t) {
  211.     String *l;
  212.     if (!s) s = curState;
  213.     if (!s || !s->l) return;
  214.     for (l=s->l; l; l=l->next){
  215.         if (l->s[0]!='/') execute(l->s);
  216.         else
  217.         if (l->s[0]=='/' && *t && match(t,l->s+1)) execute(l->s);
  218.     }
  219. }
  220.  
  221. void
  222. runState(char *s) {
  223.     execState(curState,s);
  224. }
  225.  
  226. int numItem(char *s) {
  227.     int i = 0;
  228.     State *S = state(s);
  229.     MenuItem *m;
  230.     if (!S) return 0;
  231.     for (m=S->m; m; m=m->next) i++;
  232.     return i;
  233. }
  234.  
  235. State *curMenu;
  236.  
  237. void setMenu(char *s) { curMenu = state(s); }
  238.  
  239. MenuItem *
  240. curMenuItem(int n) {
  241.     MenuItem *m;
  242.     if (!curMenu) return (MenuItem *)0;
  243.     for (m=curMenu->m; m && n-->0; m = m->next) ;
  244.     return m;
  245. }
  246.  
  247. static int valid(MenuItem *m) {
  248.     MenuItem *t;
  249.     if (!curMenu) return 0;
  250.     for (t=curMenu->m; t; t=t->next)
  251.         if (t==m) return 1;
  252.     return 0;
  253. }
  254.  
  255.  
  256. char *getLabel(MenuItem *m) { return valid(m)? m->label : ""; }
  257. char *getSend(MenuItem *m) { return valid(m)? m->send : ""; }
  258. char *getGet(MenuItem *m) { return valid(m)? m->get : ""; }
  259. char *curMenuFirst(void) { return curMenu? curMenu->first : "**nada**"; }
  260. char *curMenuLast(void) { return curMenu? curMenu->last : "**nada**"; }
  261.  
  262. char *
  263. getReport(char *buf) {
  264.     char *p = buf+1;
  265.     int starting = 1;
  266.     strcpy(buf,"\n");
  267.     while (pgets(p,1024) && !strindex(p,curMenuFirst())){
  268.     if (Verbose) printf("+%s",p);
  269.     if (starting && strlen(p)<=5)
  270.         ;
  271.     else
  272.     if (strindex(p,"Enter 3-letter") || strindex(p,"Enter 2-letter")
  273.             || strindex(p,"Selection:"))
  274.         ;
  275.     else
  276.     if (strindex(p,"ress return") || strindex(p,"ress Return"))
  277.         Put("\n");
  278.     else
  279.         starting = 0, p += strlen(p);
  280.     }
  281.     *p = '\0';
  282.     if (curMenu) Flush(curMenuLast());
  283.     return buf;
  284. }
  285.  
  286. MenuItem *
  287. menuFor(char *label, char *name) {
  288.     int i;
  289.     MenuItem *m;
  290.     *name = '\0';
  291.     for (i=0;i<NS;i++){
  292.         if (ST[i]->type == MENU){
  293.             for (m=ST[i]->m;m;m=m->next)
  294.                 if (strcmp(label,m->label)==0){
  295.                     strcpy(name,ST[i]->name);
  296.                     return m;
  297.                 }
  298.         }
  299.     }
  300.     return (MenuItem *)0;
  301. }
  302.  
  303. #define hackflush() sleep(1); while (pgets(hack,1024) && !strindex(hack,curMenuLast())) if (Verbose) printf("+%s",hack)
  304.  
  305. void
  306. fetchReport(char *label, char *buf) {
  307.     char menu[256];
  308.     char hack[1024];
  309.     MenuItem *m = menuFor(label,menu);
  310.     *buf = '\0';
  311.     if (!m) return;
  312.  
  313.     {
  314.         State *s = state("Main");
  315.         MenuItem *t = s->m;
  316.         for (;t && strcmp(t->get,menu);t=t->next) ;
  317.         if (t)
  318.             Put("%s",t->send);
  319.     }
  320.     setMenu(menu); hackflush();
  321.     Put("%s",m->send);
  322.     if (strcmp(menu,"Main")==0) pgets(hack,1024);
  323.     getReport(buf);
  324.     if (strcmp(curMenu->name,"Main")){
  325.         Put("m\n"), setMenu("Main");
  326.         hackflush();
  327.     } else
  328.         hackflush();
  329. }
  330.  
  331. /*
  332.  
  333. void print(void){
  334.     int i;
  335.     for (i=0;i<NS;i++) printState(ST[i]);
  336. }
  337.  
  338. int main(main){
  339.     char s[1024];
  340.     ReadState("states");
  341.     print();
  342.     setState("Attach");
  343.     *s = '\0';
  344.     do { runState(s); } while (gets(s));
  345. }
  346. */
  347.